#pragma once
#include <iostream>
#include <pthread.h>
#include <vector>
#include "Sem.hpp"
#include "Mutex.hpp"
#include "LockGuard.hpp"

static const int g_default_capacity = 6;

// 基于多生产多消费的环形队列
template <class T>
class RingQueue
{
public:
    // 构造函数
    RingQueue(int capacity = g_default_capacity)
        :_capacity(capacity)
        ,_proIndex(0)
        ,_conIndex(0)
        ,_ringQueue(capacity)
        ,_proSpace(capacity)
        ,_conData(0)
    {
    }

    // 析构函数
    ~RingQueue()
    {
    }

    // 生产者
    void Push(const T &in)
    {   
        // 生产者先预定空间资源,即空间资源减少
        _proSpace.p_Operator();

        {
            LockGuard lg(_proLock);
            
            _ringQueue[_proIndex++]=in;
            _proIndex%=_capacity;
        }
        
        // 生产完毕则让数据资源增加
        _conData.v_Operator();
    }

    // 消费者
    void Pop(T *out)
    {
        // 消费者先预定数据资源,即数据资源减少
        _conData.p_Operator();
        {
            LockGuard lg(_conLock);

            *out=_ringQueue[_conIndex++];
            _conIndex%=_capacity;
        }
        // 获取到数据资源后则让空间资源增加
        _proSpace.v_Operator();
    }

private:
    int _capacity;             // 环形队列的容量
    int _proIndex;             // 生产者对应的下标
    int _conIndex;             // 消费者对应的下标
    std::vector<T> _ringQueue; // 环形队列

    Sem _proSpace; // 标识生产者还有多少空间资源
    Sem _conData; // 标识消费者还有多少数据资源

    Mutex _proLock; // 多生产者之间的互斥锁
    Mutex _conLock; // 多消费者之间的互斥锁
};